﻿using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;

namespace eslib.nnp5
{
    /// <summary>
    /// 连接抽象
    /// </summary>
    public abstract class Connector : IDisposable
    {
        #region 需要重写部分

        /// <summary>
        /// 连接目标,异常时应调用InvokeConnectFailEvent
        /// </summary>
        /// <returns></returns>
        public abstract bool connect();


        /// <summary>
        /// 异步连接目标,异常时应调用InvokeConnectFailEvent
        /// </summary>
        public abstract void beginConnect();


        /// <summary>
        /// 重新连接上次连接的服务器（只适用于初次连接失败时使用）
        /// </summary>
        public abstract void reConnect();


        /// <summary>
        /// 发送字节流
        /// </summary>
        /// <param name="buffer"></param>
        public abstract void send(byte[] buffer);

        /// <summary>
        /// 关闭连接
        /// </summary>
        public abstract void close();


        /// <summary>
        /// 克隆连接器（只复制连接信息）
        /// </summary>
        /// <returns></returns>
        public abstract Connector Clone();
        #endregion




        #region 自动重连


        /// <summary>
        /// 是否开启连接失败时自动重连(默认false)
        /// </summary>
        public bool EnableReconnectOnConnectFailEvent { get; set; } = false;



        //内部连接失败事件
        private void connectFailEvent()
        {
            Debug.WriteLine("Connector连接失败");
            if (EnableReconnectOnConnectFailEvent)
            {
                Debug.WriteLine("5秒后重新连接");
                Thread.Sleep(5000);

                reConnect();
                Debug.WriteLine("Connector正在重连...");
            }
        }



        #endregion








        /// <summary>
        /// 接收到字节流时引发
        /// </summary>
        public event RecvEventHandler RecvEvent;
        protected void InvokeRecvEvent(byte[] buffer, int len)
        {
            RecvEvent?.Invoke(this, buffer, len);
        }

        /// <summary>
        /// [异步事件]连接成功时引发
        /// </summary>
        public event ConnectSuccessEventHandler ConnectSuccessEvent;
        protected void InvokeConnectSuccesEvent()
        {
            Task.Run(() =>
           {
               ConnectSuccessEvent?.Invoke(this);
           });
        }



        /// <summary>
        /// [异步事件]连接失败时引发
        /// </summary>
        public event ConnectFailEventHandler ConnectFailEvent;
        protected void InvokeConnectFailEvent(string message)
        {
            Task.Run(() =>
            {
                connectFailEvent();     //引发内部事件
                ConnectFailEvent?.Invoke(message);
            });
        }

        /// <summary>
        /// [异步事件]连接断开时引发
        /// </summary>
        public event DisconnectEventHandler DisconnectEvent;
        protected void InvokeDisconnectEvent(string message)
        {
            Task.Run(() =>
            {
                DisconnectEvent?.Invoke(this, message);
            });
        }




        #region IDisposable Support
        private bool disposedValue = false; // 要检测冗余调用

        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    // TODO: 释放托管状态(托管对象)。
                }

                // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。
                // TODO: 将大型字段设置为 null。
                close();

                disposedValue = true;
            }
        }

        // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。
        // ~Connector() {
        //   // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
        //   Dispose(false);
        // }

        // 添加此代码以正确实现可处置模式。
        public void Dispose()
        {
            // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。
            Dispose(true);
            // TODO: 如果在以上内容中替代了终结器，则取消注释以下行。
            // GC.SuppressFinalize(this);
        }
        #endregion

    }




    /// <summary>
    /// 连接成功委托
    /// </summary>
    public delegate void ConnectSuccessEventHandler(Connector connector);

    /// <summary>
    /// 连接失败委托
    /// </summary>
    /// <param name="message"></param>
    public delegate void ConnectFailEventHandler(string message);

    /// <summary>
    /// 连接断开委托
    /// </summary>
    /// <param name="connector"></param>
    public delegate void DisconnectEventHandler(Connector connector, string message);


    /// <summary>
    /// 字节流接收事件委托
    /// </summary>
    /// <param name="buffer"></param>    
    public delegate void RecvEventHandler(Connector connector, byte[] buffer, int len);
}
